import requests
from lxml import etree
from openpyxl import Workbook
import re
from fontTools.ttLib import TTFont


headers = {
    'Referer': 'https://www.dianping.com/',
    'Host': 'www.dianping.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36',
    'Cookie': '_lxsdk_cuid=17739884850c8-08129ef5936e95-c791e37-1fa400-17739884850c8; _lxsdk=17739884850c8-08129ef5936e95-c791e37-1fa400-17739884850c8; _hc.v=fe35843f-8279-52d3-458f-64e54125abce.1611577969; s_ViewType=10; ctu=739da695a9d02b38fdd5dae578f668f7e4a8f3bae960bc89c668a695a11598ff; fspop=test; cy=2; cye=beijing; _dp.ac.v=e7f567f9-8914-4d49-8c13-6887f3ecc32d; Hm_lvt_602b80cf8079ae6591966cc70a3940e7=1611579785,1611579860,1611579926,1611625175; _lx_utm=utm_source%3Dgoogle%26utm_medium%3Dorganic; lgtoken=04b8a9f65-d093-4552-b43c-794702bf7f2a; dper=366cef8b0805f224ae91f78bdaa38ea988f876e18f8d590df117472937f97f9baa67c3b6aef9021c6bb729ebf4dc54f33e34763203fe8443041257a84e16ad533f4c7343758cb35d76512d057ca50fcd35cf18ce034f379f8a61bcc73fcee662; ll=7fd06e815b796be3df069dec7836c3df; ua=17060343693; dplet=2fec7342bfb27e8228a5e7f40ff5f660; Hm_lpvt_602b80cf8079ae6591966cc70a3940e7=1611633877; _lxsdk_s=1773c5896c2-a3b-3f-658%7C%7C1088'
}
# proxy = {'http': 'http://' + requests.get('http://127.0.0.1:5000/get').text}
patten = re.compile(r'textLength="(.*?)"')
work = Workbook()
w = work.active
w.append(
    ['餐厅名称', '所处类别', '口味评分', '环境评分', '服务评分',
     '人均消费', '餐厅营业时间', '总评分',
     '评论总数', '餐厅位置信息', '评论者名字', '每条评论具体内容',
     '评论的评论', '评论的浏览', '评论排序', '评论时间',
     '评论打分(口味)', '评论人均消费', '是否有图片',
     '评论者粉丝', '评论者关注', '评论获赞'])
# 获取svg文件及对应的字体css文件
url_svg = 'http://s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/08ef8d8f10080d81ae3ba79ac999e6b8.svg'
svg_resp = requests.get(url=url_svg).text
url_svg_p = 'http://s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/1ac4280822fdd2f06038703fc416045c.svg'
svg_resp_p = requests.get(url=url_svg_p).text
length = patten.findall(svg_resp)
url_css = 'http://s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/60790d2b8f057df9948765cda42316d4.css'
css_resp = requests.get(url=url_css).text


# 获取列表页中所有的店铺url及评分
def get_all_url():
    start_urls = ['http://www.dianping.com/beijing/ch10/g101o2']
    for url in start_urls:
        response = requests.get(url=url, headers=headers).text
        with open('2.html', 'w', encoding='utf-8') as f:
            f.write(response)
        html = etree.HTML(response)
        url_list = html.xpath('//li[@class=""]/div[@class="pic"]/a/@href')[:5]
        score_list = html.xpath('//div[@class="nebula_star"]/div[2]/text()')[:5]
        return url_list, score_list


# 获取破解以后的页面
def gen_html(url_lst, score_list):
    for i in range(len(url_lst)):
        response = requests.get(url=url_lst[i] + f'/review_all', headers=headers).text
        html = etree.HTML(response)
        evaluate_number = html.xpath('//*[@id="review-list"]/div[2]/div[1]/div[2]/span[1]/text()')[0].split('条')[0]
        # 限制了评论的数量
        if int(evaluate_number) >= 2000:
            num = 150
        else:
            num = int(evaluate_number) // 15 + 1
        for page in range(67, num):
            review_url = url_lst[i] + f'/review_all/p{page}'
            response = requests.get(url=review_url, headers=headers).text
            html = etree.HTML(response)
            # 替换页面中的字体加密
            css_name_list = html.xpath('//svgmtsi/@class')
            css = css_resp.replace('\n', '').replace(' ', '')
            p_css_name_list = html.xpath('//bb/@class')
            p_css = css_resp.replace('\n', '').replace(' ', '')
            saveHtml_saveWoff(url_lst[i])
            time_html = get_info()
            response = trance_position(p_css_name_list, p_css, response)
            response = trance_chart(css_name_list, css, response)
            with open("4.html", "w", encoding="utf-8", errors="ignnore") as f:
                f.write(response)
            html = etree.HTML(response)
            get_detail(html, time_html, score_list, i, page)


# 获取页面内容并存储
def get_detail(html, time_html, score_list, i, page):
    # 获取页面内容
    title = html.xpath('//*[@id="review-list"]/div[2]/div[1]/div[1]/h1/text()')[0]
    # 评论的总量
    evaluate_number = html.xpath('//*[@id="review-list"]/div[2]/div[1]/div[2]/span[1]/text()')[0]
    # 平均消费
    avg = html.xpath('//*[@id="review-list"]/div[2]/div[1]/div[2]/span[2]/text()')[0]
    # 产品或者口味
    product = html.xpath('//*[@id="review-list"]/div[2]/div[1]/div[2]/span[3]/span[1]/text()')[0]
    # 环境
    et = html.xpath('//*[@id="review-list"]/div[2]/div[1]/div[2]/span[3]/span[2]/text()')[0]
    # 服务
    fw = html.xpath('//*[@id="review-list"]/div[2]/div[1]/div[2]/span[3]/span[3]/text()')[0]
    # 开业时间
    open_time = ''.join(time_html.xpath('//p[@class="info info-indent"]/span//text()'))
    # 评论的用户名
    name_list = html.xpath('//a[@class="name"]/text()')
    # 总评分
    avg_score = score_list[i]
    # 获取评论
    element_list = [i.strip() for i in ''.join(
        [i.strip('\n').replace('\n', '') for i in
         html.xpath('//div[@class="review-words Hide"]/text()')]).split(
        '\t')]
    # 评论排序
    sort = [str(i + (page - 1) * 15) for i in range(1, len(name_list) + 1)]
    # 评论的时间
    ev_time = html.xpath('//span[@class="time"]/text()')
    # 评论的评分
    ev_score = html.xpath('//span[@class="score"]/span[1]/text()')
    # 评论的平均消费
    ev_avg = html.xpath('//span[@class="score"]')
    # 评论者url
    evor_url_list = html.xpath('//a[@class="name"]/@href')
    ev_list = []
    for j in ev_avg:
        if j.xpath('./span[5]/text()'):
            j = j.xpath('./span[5]/text()')[0].strip().split('：')[1]
        else:
            j = '无'
        ev_list.append(j)
    review = html.xpath('//div[@class="main-review"]')
    # 判断有没有图片
    picture_list = []
    for q in review:
        is_picture = q.xpath('./div[@class="review-pictures"]/ul')
        if is_picture:
            q = '是'
        else:
            q = '否'
        picture_list.append(q)
    # 获取定位
    position = ''.join(html.xpath('//div[@class="address-info"]/text()'))
    # 处理评论者信息字体加密
    k = 0
    for j in range(len(name_list)):
        if name_list[j].strip() == '匿名用户':
            focus, fans, praise, read = ['无', '无', '无', '无']
        else:
            envor_url = 'http://www.dianping.com' + evor_url_list[k]
            k += 1
            # 评论者的关注，粉丝，点赞
            focus, fans, praise = tran_envor(envor_url)
        # 评论的浏览量
        glance = ''.join(html.xpath(f'//em[@class="col-exp"][{j + 1}]/text()'))
        # 需要存储的内容
        message_list = [title, '本帮江泽菜', product.split('：')[1], et.split('：')[1], fw.split('：')[1],
                        avg.split('：')[1], open_time, avg_score,
                        evaluate_number.split('条')[0],
                        position.strip(), name_list[j].strip(), element_list[j],
                        glance.strip('(').strip(')'),
                        sort[j], ev_time[j], ev_score[j].strip().split('：')[1], ev_list[j], picture_list[j],
                        focus, fans,
                        praise]
        w.append(message_list)
        work.save('大众点评.xlsx')


# 处理位置字体加密，是（x,y）型的
def trance_position(p_css_name_list, p_css, response):
    for p_css_name in p_css_name_list:
        pattern = re.compile(r'\.%s{background:-(\d+).0px-(\d+).0px;}' % p_css_name)
        p_coord = pattern.findall(p_css)
        if p_coord:
            x, y = p_coord[0]
            x, y = int(x), int(y)
            y_patten = re.compile(r'y="(.*?)">')
            y_list = y_patten.findall(svg_resp_p)
            axis_y = [i for i in y_list if y <= int(i)][0]
            chart_patten = re.compile(r'y="%s">(.*?)<' % axis_y)
            chart = chart_patten.findall(svg_resp_p)[0][x // 14]
            response = response.replace(f'<bb class="{p_css_name}"></bb>', chart)
    return response


# 处理评论字体加密，是（id,text_length）型的
def trance_chart(css_name_list, css, response):
    for css_name in css_name_list:
        pattern = re.compile(r'\.%s{background:-(\d+).0px-(\d+).0px;}' % css_name)
        coord = pattern.findall(css)
        if coord:
            x, y = coord[0]
            x, y = int(x), int(y)
            num_patten = re.compile('id="(.*?)" d="M0 (.*?) H')
            number_list = num_patten.findall(svg_resp)
            axis_y = [(i, j) for i, j in number_list if y <= int(j)][0]
            chart_patten = re.compile(r'href="#%s".*>(.*?)<' % axis_y[0])
            chart = chart_patten.findall(svg_resp)[0][x // 14]
            response = response.replace(f'<svgmtsi class="{css_name}"></svgmtsi>', chart)
            response = response.replace(f'<bb class="{css_name}"></bb>', chart)
    return response


# 处理营业时间woff文件字体加密
def saveHtml_saveWoff(i):  # 保存相应的html 和 此次的woff字体
    url = i
    res = requests.get(url=url, headers=headers).text
    with open("1.html", "w", encoding="utf-8", errors="ignnore") as f:
        f.write(res)
    # 先抓取css,找到woff文件链接,保存字体
    css_href_list = re.findall(r'href="(//s3plus\.meituan\.net/v1.{,100}?)"', res, re.S)
    if css_href_list:
        css_href = "http:" + css_href_list[0]
        text = requests.get(css_href).text
        # 营业时间中文字体
        pos_woff_url = re.findall(r'(//s3plus\.meituan\.net/.{,100}?woff)', text)[1]
        # 营业时间数字
        hours_woff_url = re.findall(r'(//s3plus\.meituan\.net/.{,100}?woff)', text)[-1]
        pos_content = requests.get("http:" + pos_woff_url).content
        hours_content = requests.get("http:" + hours_woff_url).content
        with open(f"pos.woff", "wb") as f:
            f.write(pos_content)
        with open('hours.woff', "wb") as f:
            f.write(hours_content)


# 构建字体映射
def get_font_map(woff_file):
    font = TTFont(woff_file)
    font_names = font.getGlyphOrder()[2:]  # getGlyphOrder()方法返回所有字符编码名称，按表格顺序提取，类型为列表
    woff_list = ['1', '2', '3', '4', '5', '6', '7', '8',
                 '9', '0', '店', '中', '美', '家', '馆', '小', '车', '大',
                 '市', '公', '酒', '行', '国', '品', '发', '电', '金', '心',
                 '业', '商', '司', '超', '生', '装', '园', '场', '食', '有',
                 '新', '限', '天', '面', '工', '服', '海', '华', '水', '房',
                 '饰', '城', '乐', '汽', '香', '部', '利', '子', '老', '艺',
                 '花', '专', '东', '肉', '菜', '学', '福', '饭', '人', '百',
                 '餐', '茶', '务', '通', '味', '所', '山', '区', '门', '药',
                 '银', '农', '龙', '停', '尚', '安', '广', '鑫', '一', '容',
                 '动', '南', '具', '源', '兴', '鲜', '记', '时', '机', '烤',
                 '文', '康', '信', '果', '阳', '理', '锅', '宝', '达', '地',
                 '儿', '衣', '特', '产', '西', '批', '坊', '州', '牛', '佳',
                 '化', '五', '米', '修', '爱', '北', '养', '卖', '建', '材',
                 '三', '会', '鸡', '室', '红', '站', '德', '王', '光', '名',
                 '丽', '油', '院', '堂', '烧', '江', '社', '合', '星', '货',
                 '型', '村', '自', '科', '快', '便', '日', '民', '营', '和',
                 '活', '童', '明', '器', '烟', '育', '宾', '精', '屋', '经',
                 '居', '庄', '石', '顺', '林', '尔', '县', '手', '厅', '销',
                 '用', '好', '客', '火', '雅', '盛', '体', '旅', '之', '鞋',
                 '辣', '作', '粉', '包', '楼', '校', '鱼', '平', '彩', '上',
                 '吧', '保', '永', '万', '物', '教', '吃', '设', '医', '正',
                 '造', '丰', '健', '点', '汤', '网', '庆', '技', '斯', '洗',
                 '料', '配', '汇', '木', '缘', '加', '麻', '联', '卫', '川',
                 '泰', '色', '世', '方', '寓', '风', '幼', '羊', '烫', '来',
                 '高', '厂', '兰', '阿', '贝', '皮', '全', '女', '拉', '成',
                 '云', '维', '贸', '道', '术', '运', '都', '口', '博', '河',
                 '瑞', '宏', '京', '际', '路', '祥', '青', '镇', '厨', '培',
                 '力', '惠', '连', '马', '鸿', '钢', '训', '影', '甲', '助',
                 '窗', '布', '富', '牌', '头', '四', '多', '妆', '吉', '苑',
                 '沙', '恒', '隆', '春', '干', '饼', '氏', '里', '二', '管',
                 '诚', '制', '售', '嘉', '长', '轩', '杂', '副', '清', '计',
                 '黄', '讯', '太', '鸭', '号', '街', '交', '与', '叉', '附',
                 '近', '层', '旁', '对', '巷', '栋', '环', '省', '桥', '湖',
                 '段', '乡', '厦', '府', '铺', '内', '侧', '元', '购', '前',
                 '幢', '滨', '处', '向', '座', '下', '県', '凤', '港', '开',
                 '关', '景', '泉', '塘', '放', '昌', '线', '湾', '政', '步',
                 '宁', '解', '白', '田', '町', '溪', '十', '八', '古', '双',
                 '胜', '本', '单', '同', '九', '迎', '第', '台', '玉', '锦',
                 '底', '后', '七', '斜', '期', '武', '岭', '松', '角', '纪',
                 '朝', '峰', '六', '振', '珠', '局', '岗', '洲', '横', '边',
                 '济', '井', '办', '汉', '代', '临', '弄', '团', '外', '塔',
                 '杨', '铁', '浦', '字', '年', '岛', '陵', '原', '梅', '进',
                 '荣', '友', '虹', '央', '桂', '沿', '事', '津', '凯', '莲',
                 '丁', '秀', '柳', '集', '紫', '旗', '张', '谷', '的', '是',
                 '不', '了', '很', '还', '个', '也', '这', '我', '就', '在',
                 '以', '可', '到', '错', '没', '去', '过', '感', '次', '要',
                 '比', '觉', '看', '得', '说', '常', '真', '们', '但', '最',
                 '喜', '哈', '么', '别', '位', '能', '较', '境', '非', '为',
                 '欢', '然', '他', '挺', '着', '价', '那', '意', '种', '想',
                 '出', '员', '两', '推', '做', '排', '实', '分', '间', '甜',
                 '度', '起', '满', '给', '热', '完', '格', '荐', '喝', '等',
                 '其', '再', '几', '只', '现', '朋', '候', '样', '直', '而',
                 '买', '于', '般', '豆', '量', '选', '奶', '打', '每', '评',
                 '少', '算', '又', '因', '情', '找', '些', '份', '置', '适',
                 '什', '蛋', '师', '气', '你', '姐', '棒', '试', '总', '定',
                 '啊', '足', '级', '整', '带', '虾', '如', '态', '且', '尝',
                 '主', '话', '强', '当', '更', '板', '知', '己', '无', '酸',
                 '让', '入', '啦', '式', '笑', '赞', '片', '酱', '差', '像',
                 '提', '队', '走', '嫩', '才', '刚', '午', '接', '重', '串',
                 '回', '晚', '微', '周', '值', '费', '性', '桌', '拍', '跟',
                 '块', '调', '糕']
    texts = woff_list
    num_uni_dict = {}
    for i, uni in enumerate(font_names):
        num_uni_dict[uni.lower().replace('uni', '&#x') + ';'] = str(texts[i])
    return num_uni_dict


# 替换
def get_info():
    with open("1.html", "r", encoding="utf-8", errors="ignore") as f:
        html = f.read()
    hours_map_dict = get_font_map('hours.woff')
    pos_map_dict = get_font_map('pos.woff')
    for uni in hours_map_dict.keys():
        html = html.replace(uni, hours_map_dict[uni])
    for uni in pos_map_dict.keys():
        html = html.replace(uni, pos_map_dict[uni])
    parse_html = etree.HTML(html)
    return parse_html


# 处理评论者信息字体woff文件加密
def tran_envor(i):
    res = requests.get(url=i, headers=headers).text
    with open("3.html", "w", encoding="utf-8", errors="ignnore") as f:
        f.write(res)
    css_href_list = re.findall(r'href="(//s3plus\.meituan\.net/v1.{,100}?)"', res, re.S)
    if css_href_list:
        css_href = "http:" + css_href_list[0]
        text = requests.get(css_href).text
        envor_woff_url = re.findall(r'(//s3plus\.meituan\.net/.{,100}?woff)', text)[-2]
        pos_content = requests.get("http:" + envor_woff_url).content
        with open("fans.woff", "wb") as f:
            f.write(pos_content)
        font = TTFont("fans.woff")
        font_names = font.getGlyphOrder()[2:]  # getGlyphOrder()方法返回所有字符编码名称，按表格顺序提取，类型为列表
        woff_list = ['1', '2', '3', '4', '5', '6', '7', '8',
                     '9', '0', '店', '中', '美', '家', '馆', '小', '车', '大',
                     '市', '公', '酒', '行', '国', '品', '发', '电', '金', '心',
                     '业', '商', '司', '超', '生', '装', '园', '场', '食', '有',
                     '新', '限', '天', '面', '工', '服', '海', '华', '水', '房',
                     '饰', '城', '乐', '汽', '香', '部', '利', '子', '老', '艺',
                     '花', '专', '东', '肉', '菜', '学', '福', '饭', '人', '百',
                     '餐', '茶', '务', '通', '味', '所', '山', '区', '门', '药',
                     '银', '农', '龙', '停', '尚', '安', '广', '鑫', '一', '容',
                     '动', '南', '具', '源', '兴', '鲜', '记', '时', '机', '烤',
                     '文', '康', '信', '果', '阳', '理', '锅', '宝', '达', '地',
                     '儿', '衣', '特', '产', '西', '批', '坊', '州', '牛', '佳',
                     '化', '五', '米', '修', '爱', '北', '养', '卖', '建', '材',
                     '三', '会', '鸡', '室', '红', '站', '德', '王', '光', '名',
                     '丽', '油', '院', '堂', '烧', '江', '社', '合', '星', '货',
                     '型', '村', '自', '科', '快', '便', '日', '民', '营', '和',
                     '活', '童', '明', '器', '烟', '育', '宾', '精', '屋', '经',
                     '居', '庄', '石', '顺', '林', '尔', '县', '手', '厅', '销',
                     '用', '好', '客', '火', '雅', '盛', '体', '旅', '之', '鞋',
                     '辣', '作', '粉', '包', '楼', '校', '鱼', '平', '彩', '上',
                     '吧', '保', '永', '万', '物', '教', '吃', '设', '医', '正',
                     '造', '丰', '健', '点', '汤', '网', '庆', '技', '斯', '洗',
                     '料', '配', '汇', '木', '缘', '加', '麻', '联', '卫', '川',
                     '泰', '色', '世', '方', '寓', '风', '幼', '羊', '烫', '来',
                     '高', '厂', '兰', '阿', '贝', '皮', '全', '女', '拉', '成',
                     '云', '维', '贸', '道', '术', '运', '都', '口', '博', '河',
                     '瑞', '宏', '京', '际', '路', '祥', '青', '镇', '厨', '培',
                     '力', '惠', '连', '马', '鸿', '钢', '训', '影', '甲', '助',
                     '窗', '布', '富', '牌', '头', '四', '多', '妆', '吉', '苑',
                     '沙', '恒', '隆', '春', '干', '饼', '氏', '里', '二', '管',
                     '诚', '制', '售', '嘉', '长', '轩', '杂', '副', '清', '计',
                     '黄', '讯', '太', '鸭', '号', '街', '交', '与', '叉', '附',
                     '近', '层', '旁', '对', '巷', '栋', '环', '省', '桥', '湖',
                     '段', '乡', '厦', '府', '铺', '内', '侧', '元', '购', '前',
                     '幢', '滨', '处', '向', '座', '下', '県', '凤', '港', '开',
                     '关', '景', '泉', '塘', '放', '昌', '线', '湾', '政', '步',
                     '宁', '解', '白', '田', '町', '溪', '十', '八', '古', '双',
                     '胜', '本', '单', '同', '九', '迎', '第', '台', '玉', '锦',
                     '底', '后', '七', '斜', '期', '武', '岭', '松', '角', '纪',
                     '朝', '峰', '六', '振', '珠', '局', '岗', '洲', '横', '边',
                     '济', '井', '办', '汉', '代', '临', '弄', '团', '外', '塔',
                     '杨', '铁', '浦', '字', '年', '岛', '陵', '原', '梅', '进',
                     '荣', '友', '虹', '央', '桂', '沿', '事', '津', '凯', '莲',
                     '丁', '秀', '柳', '集', '紫', '旗', '张', '谷', '的', '是',
                     '不', '了', '很', '还', '个', '也', '这', '我', '就', '在',
                     '以', '可', '到', '错', '没', '去', '过', '感', '次', '要',
                     '比', '觉', '看', '得', '说', '常', '真', '们', '但', '最',
                     '喜', '哈', '么', '别', '位', '能', '较', '境', '非', '为',
                     '欢', '然', '他', '挺', '着', '价', '那', '意', '种', '想',
                     '出', '员', '两', '推', '做', '排', '实', '分', '间', '甜',
                     '度', '起', '满', '给', '热', '完', '格', '荐', '喝', '等',
                     '其', '再', '几', '只', '现', '朋', '候', '样', '直', '而',
                     '买', '于', '般', '豆', '量', '选', '奶', '打', '每', '评',
                     '少', '算', '又', '因', '情', '找', '些', '份', '置', '适',
                     '什', '蛋', '师', '气', '你', '姐', '棒', '试', '总', '定',
                     '啊', '足', '级', '整', '带', '虾', '如', '态', '且', '尝',
                     '主', '话', '强', '当', '更', '板', '知', '己', '无', '酸',
                     '让', '入', '啦', '式', '笑', '赞', '片', '酱', '差', '像',
                     '提', '队', '走', '嫩', '才', '刚', '午', '接', '重', '串',
                     '回', '晚', '微', '周', '值', '费', '性', '桌', '拍', '跟',
                     '块', '调', '糕']
        texts = woff_list
        num_uni_dict = {}
        for i, uni in enumerate(font_names):
            num_uni_dict[uni.lower().replace('uni', '&#x') + ';'] = str(texts[i])
        with open("3.html", "r", encoding="utf-8", errors="ignore") as f:
            html = f.read()
        for uni in num_uni_dict.keys():
            html = html.replace(uni, num_uni_dict[uni])
        parse_html = etree.HTML(html)
        focus = ''.join(parse_html.xpath('//div[@class="user_atten"]/ul/li[1]/a/strong//text()'))
        fans = ''.join(parse_html.xpath('//div[@class="user_atten"]/ul/li[2]/a/strong//text()'))
        praise = ''.join(parse_html.xpath('//div[@class="user_atten"]/ul/li[3]/strong//text()'))
        return focus, fans, praise


if __name__ == '__main__':
    pass
    url_list, score_list = get_all_url()
    gen_html(url_list, score_list)
